// podModel.go
package models

import (
	"bytes"
	"context"
	"fmt"

	"io"
	"log"
	"myk8s/common"
	"os"

	//"os"
	"strings"

	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	//"k8s.io/apimachinery/pkg/runtime"
	//"sigs.k8s.io/yaml"
)

type Podinfo struct {
	PodName   string `json:"podName"` //podname 和podip
	PodIp     string `json:"podIp"`
	NameSpace string `json:"nameSpace"`
	NodeName  string `json:"nodeName"` //节点名称和节点IP
	HostIp    string `json:"hostIp"`
	PodPhase  string `json:"podPhase"` //容器状态 Running
	ImgUrl    string `json:"imgUrl"`
	//PodStatus    PodStatusItem
	RestartCount int32  `json:"restartCount"` //重启次数
	Labels       string `json:"labels"`       //标签
	ResStatus    string `json:"resStatus"`    //cpu及内存使用率
	CreateTime   string `json:"createTime"`
}

type Container struct {
	ContainerName  string `json:"containerName"`
	Envs           string `json:"envs"`
	Mounts         string `json:"mounts"`
	ContainerImage string `json:"containerImage"`
	PullPolicy     string `json:"pullPolicy"`
	Ports          string `json:"ports"`
	ResLimits      string `json:"resLimits"`
	ResRequests    string `json:"resRequests"`
}

func PodList(kubeconfig, namespace, deployName, podName string, labelsKey, labelsValue, nodeName string) ([]Podinfo, error) {

	if namespace == "" {
		//namespace = corev1.NamespaceDefault
		namespace = corev1.NamespaceAll
	}

	clientset := common.ClientSet(kubeconfig)
	var podList *corev1.PodList
	var err error

	//设置ListOptions
	var listOptions = metav1.ListOptions{}
	if labelsKey != "" && labelsValue != "" {
		listOptions = metav1.ListOptions{
			LabelSelector: fmt.Sprintf("%s=%s", labelsKey, labelsValue),
			//FieldSelector: "status.phase=Running,spec.nodeName=ais-master1",
		}
	}

	if nodeName != "" {
		listOptions = metav1.ListOptions{
			FieldSelector: fmt.Sprintf("status.phase!=Succeeded,spec.nodeName=%s", nodeName),
		}
	}

	podList, err = clientset.CoreV1().Pods(namespace).List(context.Background(), listOptions)

	if err != nil {
		log.Printf("list pods error:%v\n", err)
	}
	var bbb = make([]Podinfo, 0)
	for _, pod := range podList.Items {
		//搜索
		if podName != "" {
			if !strings.Contains(pod.Name, podName) {
				//if !strings.HasPrefix(pod.Name,podName)
				continue
			}
		}
		if deployName != "" {
			if !strings.HasPrefix(pod.Name, deployName) {
				continue
			}
		}

		var labelsStr, imgurlStr string
		for kk, vv := range pod.ObjectMeta.Labels {
			labelsStr += fmt.Sprintf("%s:%s,", kk, vv)
		}
		if len(labelsStr) > 0 {
			labelsStr = labelsStr[0 : len(labelsStr)-1]
		}

		var containerState = fmt.Sprintf("%v", pod.Status.Phase)

		var restartNum int32
		if len(pod.Status.ContainerStatuses) > 0 {
			imgurlStr = pod.Status.ContainerStatuses[0].Image
			restartNum = pod.Status.ContainerStatuses[0].RestartCount
			if containerState == "Pending" {
				containerState = pod.Status.ContainerStatuses[0].State.Waiting.Reason
			}
		}

		Items := &Podinfo{
			PodName:      pod.Name,
			PodIp:        pod.Status.PodIP,
			ImgUrl:       imgurlStr,
			NameSpace:    pod.ObjectMeta.Namespace,
			NodeName:     pod.Spec.NodeName,
			HostIp:       pod.Status.HostIP,
			PodPhase:     containerState,
			Labels:       labelsStr,
			RestartCount: restartNum,
			CreateTime:   pod.ObjectMeta.CreationTimestamp.Format("2006-01-02 15:04:05"),
		}
		bbb = append(bbb, *Items)
	}
	return bbb, err
}

func PodContainerList(kubeconfig, nameSpace, podName string) ([]Container, error) {
	var ccc = make([]Container, 0)
	pod, err := common.ClientSet(kubeconfig).CoreV1().Pods(nameSpace).Get(context.TODO(), podName, metav1.GetOptions{})
	if err != nil {
		return ccc, err
	}
	for _, v1 := range pod.Spec.Containers {
		xItems := &Container{
			ContainerName:  v1.Name,
			Envs:           "",
			Mounts:         "",
			ContainerImage: v1.Image,
			PullPolicy:     fmt.Sprintf("%v", v1.ImagePullPolicy),
			Ports:          "",
			ResLimits:      fmt.Sprintf("CPU:%s,Memory:%s", v1.Resources.Limits.Cpu().String(), v1.Resources.Limits.Memory().String()),
			ResRequests:    fmt.Sprintf("CPU:%s,Memory:%s", v1.Resources.Requests.Cpu().String(), v1.Resources.Requests.Memory().String()),
		}
		ccc = append(ccc, *xItems)
	}
	return ccc, nil
}

func PodLog(kubeconfig, nameSpace, podName, container string, logLine int64) string {
	clientset := common.ClientSet(kubeconfig)
	pod, err := clientset.CoreV1().Pods(nameSpace).Get(context.TODO(), podName, metav1.GetOptions{})
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to get pod %q: %v\n", podName, err)
		//os.Exit(1)
	}
	// 获取指定行数日志
	//logs, err := clientset.CoreV1().Pods(nameSpace).GetLogs(podName, &corev1.PodLogOptions{TailLines: &lines})
	//获取实时日志
	var logOptions = &corev1.PodLogOptions{}
	logOptions.Follow = false     //持续输出
	logOptions.Timestamps = false //显示时间戳
	//var line int64 = 50
	if logLine > 0 {
		//line := logLine
		logOptions.TailLines = &logLine //获取多少行日志 需要指针类型https://blog.csdn.net/weixin_36469852/article/details/127432931
	}

	var containerPt *string = &container
	if container == "" {
		// [CONTAINER] (container as arg not flag) is supported as legacy behavior. See PR #10519 for more details.
		if len(pod.Spec.Containers) != 1 {
			podContainersNames := []string{}
			for _, container := range pod.Spec.Containers {
				podContainersNames = append(podContainersNames, container.Name)
			}
		} else {
			containerPt = &pod.Spec.Containers[0].Name
		}
	}
	logOptions.Container = *containerPt //指定container来获取日志，需要指针类型https://blog.csdn.net/weixin_36469852/article/details/127432931

	podLogs, err := clientset.CoreV1().Pods(nameSpace).GetLogs(podName, logOptions).Stream(context.TODO())
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to get logs for pod %q: %v\n", podName, err)
		//os.Exit(1)
		return "error"
	}
	defer podLogs.Close()

	//单次输出
	buf := new(bytes.Buffer)
	_, err = io.Copy(buf, podLogs)
	if err != nil {
		return "error copy"
	}
	return buf.String()

	//流式输出日志内容
	// buf := make([]byte, 1024)
	// for {
	// 	n, err := podLogs.Read(buf)
	// 	if err != nil && err == io.EOF {
	// 		break
	// 	}
	// 	fmt.Print(string(buf[0:n]))
	// }
	// return "test"
}
